//
//  OAuthViewModel.m
//  OSChina
//
//  Created by 8b410-2 on 16/12/22.
//  Copyright © 2016年 abb. All rights reserved.
//

#import "OSCOAuthViewModel.h"
#import "OSCNetAPIClient.h"
@interface OSCOAuthViewModel ()
/// 账户模型
@property (strong,nonatomic)OSCAccount *account;
/// 验证email
@property (strong,nonatomic)RACSignal *validationEmail;
/// 验证pwd
@property (strong,nonatomic)RACSignal *validationPassword;
/// 账户验证失败次数
@property (assign,nonatomic)NSInteger failCount;
/// 验证码错误代码
@property (assign,nonatomic)NSInteger captchaErrorCode;
/// 用户信息请求
@property (strong,nonatomic)RACCommand *userInfoCommand;
@end
@implementation OSCOAuthViewModel

- (instancetype)initWithServices:(id<OSCViewModelServices>)services params:(NSDictionary *)params {
    self = [super initWithServices:services params:params];
    if (self) {
        _oauthParams = [[OSCOAuthRequestParams alloc] initWithGrantType:GrantTypeCode];
        _validationAccountParams = [[OSCValidationAccountRequestParams alloc] init];
    }
    return self;
}
- (NSURL *)oauthUrl {
    if (!_oauthUrl) {
        NSString *urlStr = [NSString stringWithFormat:@"https://www.oschina.net/action/oauth2/authorize?response_type=code&client_id=%@&redirect_uri=%@",_oauthParams.client_id,_oauthParams.redirect_uri];
        _oauthUrl = [[NSURL alloc] initWithString:urlStr];
    }
    return _oauthUrl;
}
- (NSString *)jsForRequestCode {
   return @"var s=''; \
      var obj=document.getElementsByName('scope_node'); \
      for(var i=0; i<obj.length; i++){ \
          if(obj[i].checked) s+=obj[i].value+',';  \
      } \
      $(\"input[name='scope']\").val(s); \
      $('#f_pwd').val(CryptoJS.SHA1($('#f_pwd').val()).toString()); \
      $('#frm_approve').submit();";
}
- (NSString *)jsForCaptchaImageUrl {
    return @"'/action/user/captcha?t='+Math.random(1000)";
}
- (NSString *)jsForEncryptionPassword:(NSString *)password {
    return [NSString stringWithFormat:@"CryptoJS.SHA1('%@').toString()",password];
}
- (NSString *)stringForJsTagById:(NSString *)tagId {
    return [NSString stringWithFormat:@"$('#%@').val()",tagId];
}
- (NSString *)stringForSetValue:(NSString *)value ForJsTagById:(NSString *)tagId {
    NSLog(@"%@",[NSString stringWithFormat:@"$('#%@').val('%@')",tagId,value]);
    return [NSString stringWithFormat:@"$('#%@').val('%@')",tagId,value];
}

/**
 通过oschina的源码得知,获取code前先进行账户验证,需要传 'email','pwd','verifyCode'三个参数
 其中验证码在<验证失败>的前两次可不传,在<验证失败>后会返回 'failCount'或 'error' 以及 'msg' 两个字段
 'failCount'    => 用户名密码输入错误次数;
 'error'        => 恒为 1,在验证码错误时返回;
 'msg'          => 错误信息,可直接用为hud显示字符;
 =================
 为什么还要使用webView
 =================
 1.第一次访问OAuth链接时,会自动加载验证码,就算验证码输入框是隐藏的,这时候会返回一个response cookie 字段是 '_reg_key_'
 当前两次密码错误时不会再请求验证码,只有当failCount> 2 ||error == 1 时会通过js调一个新的验证码,我们用webView加载后
 可获取第一次的验证码,即能获取到请求验证码所需的cookie.
 2.账号验证成功后网页会把表单会post到'/action/oauth2/authorize',然后重定向到回调地址上,在回调地址里有一code需要获取
 此链接当然可在response header拿到,只是此表单里还有一些其他参数,加上之前写好了webView的代码.故就保留用webView获取code了
 3.密码加密需要的方法只有通过js调用
 */
- (RACCommand *)validationCommand {
    if (!_validationCommand) {
         @weakify(self);
        _validationCommand = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
            @strongify(self);
            return [[OSCAccountTools
                    requestValidationAccountWithParamsModel:self.validationAccountParams]
                    takeUntil:self.rac_willDeallocSignal];
        }];
        RAC(self,validationAccount) = [_validationCommand.executionSignals.flatten map:^id(OSCValidationAccount *validationAccount) {
            return @(!validationAccount.failCount && !validationAccount.error);
        }];
        RAC(self,showCaptchaView) = [_validationCommand.executionSignals.flatten map:^id(OSCValidationAccount *validationAccount) {
            return @(validationAccount.failCount > 2 || validationAccount.error == 1);
        }];
    }
    return _validationCommand;
}
- (RACCommand *)tokenCommand {
    if (!_tokenCommand) {
         @weakify(self);
        _tokenCommand = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
            @strongify(self);
           return [[OSCAccountTools
                    requestTokenWithParamsModel:self.oauthParams]
                   takeUntil:self.cancelSignal];
        }];
        [_tokenCommand.executionSignals.switchToLatest
         subscribeNext:^(OSCAccount *account) {
             self.account = account;
             [self.userInfoCommand execute:nil];
         }];
    }
    return _tokenCommand;
}
- (RACCommand *)userInfoCommand {
    if (!_userInfoCommand) {
         @weakify(self);
        _userInfoCommand = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
            @strongify(self);
            return [[OSCAccountTools
                    requestUserWithParamsModel:[[OSCBaseRequestParams alloc] initWithAccountToken:self.account.access_token]]
                    takeUntil:self.cancelSignal];
        }];
        [_userInfoCommand.executionSignals.switchToLatest
         subscribeNext:^(OSCUser *user) {
             @strongify(self);
            [self.account setValue:user forKey:NSStringFromSelector(@selector(user))];
            [[OSCAccountTools shareSession] loginSuccess:self.account];
            [self dismissViewModel];
        }];
    }
    return _userInfoCommand;
}
- (RACSignal *)validationEmail {
    if (!_validationEmail) {
        _validationEmail = [RACObserve(self.validationAccountParams, email)
                            map:^id(NSString *email) {
                                return @(email.length > 0);
                            }];
    }
    return _validationEmail;
}
- (RACSignal *)validationPassword {
    if (!_validationPassword) {
        _validationPassword = [RACObserve(self.validationAccountParams, pwd)
                               map:^id(NSString *password) {
                                   return @(password.length > 0);
                               }];
    }
    return _validationPassword;
}
- (RACSignal *)enableLoginActive {
    if (!_enableLoginActive) {
        _enableLoginActive = [RACSignal
                              combineLatest:@[self.validationEmail,
                                              self.validationPassword
                                              ]
                              reduce:^id(NSNumber *email,NSNumber *pwd){
                                  return @([email boolValue] && [pwd boolValue]);
                              }];
    }
    return _enableLoginActive;
}
- (void)dismissViewModel {
    [self.services dismissViewModelAnimated:YES completion:nil];
}
@end
